﻿using System;
using System.Collections.Specialized;
using System.Globalization;
using System.Web.Security;
using NStore.Domain;
using NStore.Infrastructure.Repositories;

namespace NStore.Infrastructure.Security
{
    public class NStoreMembershipProvider : MembershipProvider
    {
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            if (password.Length < _minRequiredPasswordLength)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }
            if (providerUserKey != null)
                throw new ArgumentException("Parameter 'providerUserKey' should be null");

            try
            {
                bool isUserNew;

                // Step 1: Check if the user exists in the Users table: create if not create it
                int uid = GetUserID(username, out isUserNew);

                if (uid != 0)
                { // User Found!
                    status = MembershipCreateStatus.DuplicateUserName;
                    return null;
                }
                if (!isUserNew)
                {
                    status = MembershipCreateStatus.DuplicateUserName;
                    return null;
                }

                // Step 4: Create user in Membership table					

                User usr = InsertUserData(username, email, password, isApproved);
                if (usr == null)
                {
                    status = MembershipCreateStatus.ProviderError;
                    return null;
                }

                status = MembershipCreateStatus.Success;

                return usr;
            }
            catch (Exception)
            {
                status = MembershipCreateStatus.ProviderError;
                return null;
            }
        }

        private User InsertUserData(string username, string email, string password, bool isApproved)
        {
            User user = UserRepository.GetByUserName(username);
            if (user != null)
                return null;
            user = new User(username, password) {Email = email, IsApproved = isApproved};
            UserRepository.Add(user);
            return user;
        }

        private int GetUserID(string username, out bool isUserNew)
        {
            isUserNew = false;
            User usr = UserRepository.GetByUserName(username);
            if (usr != null)
                return usr.Id;

            isUserNew = true;

            //Something went wrong
            return 0;
        }
        
        public NStoreMembershipProvider() : this(new UserRepository()) { }

        public NStoreMembershipProvider(UserRepository userRepository)
        {
            _userRepository = userRepository;
        }

        private readonly UserRepository _userRepository;
        protected UserRepository UserRepository
        {
            get { return _userRepository; }
        }

        private int _minRequiredPasswordLength;
        public override int MinRequiredPasswordLength
        {
            get { return _minRequiredPasswordLength; }
        }

        public override bool ValidateUser(string username, string password)
        {
            User user = UserRepository.GetByUserName(username);
            return user != null && user.ValidatePassword(password);
        }

        public override string ApplicationName { get; set; }

        public override void Initialize(string name, NameValueCollection config)
        {
            base.Initialize(name, config);
            _minRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", 6, false, 128);
        }

        private static int GetIntValue(NameValueCollection config, string valueName, int defaultValue, bool zeroAllowed, int maxValueAllowed)
        {
            string sValue = config[valueName];

            if (sValue == null)
                return defaultValue;

            int iValue;
            try
            {
                iValue = Convert.ToInt32(sValue, CultureInfo.InvariantCulture);
            }
            catch (FormatException e)
            {
                if (zeroAllowed)
                    throw new FormatException("El valor ha de ser un entero positivo para la propiedad '" + valueName + "'", e);

                throw new FormatException("El valor ha de ser un entero positivo para la propiedad '" + valueName + "'", e);
            }

            if (zeroAllowed && iValue < 0)
                throw new FormatException("El valor no puede ser negativo para la propiedad '" + valueName + "'");

            if (!zeroAllowed && iValue <= 0)
                throw new FormatException("El valor no puede ser negativo para la propiedad '" + valueName + "'");

            if (maxValueAllowed > 0 && iValue > maxValueAllowed)
                throw new FormatException("El valor para la propiedad '" + valueName + "' tiene que ser menor que " + maxValueAllowed.ToString(CultureInfo.InvariantCulture));

            return iValue;
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            return UserRepository.GetByUserName(username);
        }

        #region "NotImplementedException"
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        

        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); }
        }

        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }
        #endregion

    }
}
